<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * MYModel Model Extension for CodeIgniter
 *
 * This overrides the CI native Model class by adding a slew of CRUD, form
 * generation, and other methods that, if used properly, will simplify your life
 * and eliminate a lot of DRY stuff.
 *
 * For full documentation, go to http://code.google.com/p/ciheadstart
 *  
 * Hook Reference: (work the same as normal hooks)
 * 
 * 	Use $db_hook as the array name in the hooks.php file
 *  	// - pre_insert					- pre-update
 *		// - insert							- update
 *		// - pre_delete					- pre_any_change
 *		// - delete							- any_change
 *
 * @author Casey McLaughlin
 * @package CIHeadStart
 * @link http://code.google.com/p/ciheadstart
 */
class MY_Model extends Model
{
	var $error_log;
	var $hooks;
	var $table_name;
	var $form_types;
	
	// --------------------------------------------------------------------

	/**
	 * Constructor
	 * 
	 * Does a lot of stuff :)
	 *
	 * @access public
	 * @return MY_Model
	 */
	function MY_Model()
	{
		//Begin constructor
		parent::Model();

		//Initialize some stuff
		$this->error_log = array();
		$this->load->database();
		
		//Require PHP5
		if (phpversion() < 5.1)
			return show_error("You must be running at least PHP5.1 to use MyModel");
		if ( ! function_exists('json_decode'))
			return show_error("You must have the JSON extension installed (this is prepackaged with PHP5.2 and above)");

		//Set the table name if not already set
		if ( ! $this->table_name OR $this->table_name == NULL)
			$this->table_name = trim(str_replace("_model", "", strtolower(get_class($this))));
						
		//Load the db_hooks
		$this->_load_db_hooks();

		//Setup the types
		$this->_setup_form_types();

		//End constructor
		parent::Model();
	}

	// --------------------------------------------------------------------

	/**
	 * Create (INSERT) a record in the database
	 * 
	 * Accepts an array of fieldnames and their values.  Set $return_id for
	 * this function to return the ID of the newly inserted row upon successful
	 * INSERT
	 *
	 * @param array|object $input_data
	 * @return boolean|int
	 */
	function create($input_data, $return_id = TRUE)
	{
		//HOOK: Pre INSERT hook
		$this->_run_hooks('pre_insert', 'pre_any_change');

		$table_name = $this->table_name;

		//Ensure that the sent data is actually, yknow.. data
		if ( ! is_array($input_data) && ! is_object($input_data))
			return $this->_do_error("You must send the data to create function in the " . get_class($this) . " model as an associative array or an object!");

		//If sent as an array, convert it an object :)
		if (is_array($input_data))
			$input_data = new ArrayObject($input_data);

		//Ensure all of the data sent corresponds to actual fields in the table
		if ( ! $this->_check_fields_exist_for_input_data($input_data))
			return $this->_do_error("Cannot create (insert) record into the database; you sent fields that don't exist in the table!  See previous errors!");

		//**Try the the insert**
		$result = $this->db->insert($table_name, $input_data);

		//If the insert failed, let us know why
		if ( ! $result)
		{
			$this->_record_error("The query you tried to create the record with was: " . $this->db->last_query());
			return $this->_do_error("Could not insert the record into the database; The database server returned the error: " . $this->_get_db_error());
		}

		//HOOK: INSERT hook
		$this->_run_hooks('insert', 'any_change');


		//Attempt to return the ID of the newly created record -- this is not 100% foolproof
		if ($return_id)
		{
			if ($the_record = $this->retrieve_single((array) $input_data))
				return $the_record->id;
		}
		else
			return TRUE;
	}

	// --------------------------------------------------------------------

	/**
	 * Retrieve records from the database
	 *
	 * @param int|array $id_or_where_clause
	 * @param boolean $expect_only_one_result
	 * @param int $offset
	 * @param int $limit
	 * @return array
	 */
	function retrieve($id_or_where_clause = NULL, $expect_only_one_result = FALSE, $offset = NULL, $limit = NULL)
	{
		if (is_string($id_or_where_clause))
			$id_or_where_clause = trim($id_or_where_clause);

		if ( ! is_array($id_or_where_clause) && is_numeric($id_or_where_clause))
			$where = array('id' => $id_or_where_clause);
		elseif( ! is_null($id_or_where_clause))
			$where = $id_or_where_clause;
			
		if (is_int($offset))
			$this->db->offset($offset);
		if (is_int($limit))
			$this->db->limit($limit);
			
		if (isset($where))
			$query = $this->db->get_where($this->table_name, $where);
		else
			$query = $this->db->get($this->table_name);

		if ($expect_only_one_result)
		{
			if ($query->num_rows > 1)
				return $query->result();
			elseif ($query->num_rows == 1)
				return $query->row();
			else
				return FALSE;
		}
		else
		{
			if ($query->num_rows > 0)
				return $query->result();
			else
				return array();
		}
	}


	// --------------------------------------------------------------------

	/**
	 * Retrieves a single record from the database
	 *
	 * @param int|array $id_or_where_clause
	 * @param boolean $if_multiple_return_last Keeps this function from returning an error if multiple records were found
	 * @return object
	 */
	function retrieve_single($id_or_where_clause = NULL, $if_multiple_return_last = TRUE)
	{
		$results = $this->retrieve($id_or_where_clause, TRUE);

		if (is_array($results) && count($results) > 1)
		{
			if ($if_multiple_return_last)
				return array_pop($results);
			else
				return $this->_do_error("There were multiple results when attempting to retrieve a single record from $this->table_name using query or ID: " . $id_or_where_clause);
		}
		else
			return $results;
	}

	// --------------------------------------------------------------------

	/**
	 * Updates a record in the database
	 *
	 * @param int $id
	 * @param array|object $update_data
	 * @return boolean
	 */
	function update($id, $update_data)
	{
		//HOOK: Pre UPDATE hook
		$this->_run_hooks('pre_update', 'pre_any_change');

		$table_name = $this->table_name;

		//Ensure that the record with that ID actually exists
		if ( ! $this->check_record_exists($id))
			return $this->_do_error("Cannot update record with ID $id in the table: $table_name.  That record does not exist!");

		//Ensure that the sent data is actually, yknow.. data
		if ( ! is_array($update_data) && ! is_object($update_data))
			return $this->_do_error("You must send the data to update method in the " . get_class($this) . " model as an associative array or an object!");

		//If sent as an array, convert it an object :)
		if (is_array($update_data))
			$update_data = new ArrayObject($update_data);

		//Ensure all of the data sent corresponds to actual fields in the table
		if ( ! $this->_check_fields_exist_for_input_data($update_data))
			return $this->_do_error("Cannot create (insert) record into the database; you sent fields that don't exist in the table!  See previous errors!");

		//**Try the the insert**
		$this->db->where('id', $id);
		$result = $this->db->update($table_name, $update_data);

		//If the insert failed, let us know why
		if ( ! $result)
		{
			$this->_record_error("The query you tried to update the record with was: " . $this->db->last_query());
			return $this->_do_error("Could not update the record with ID $id in the database; The database server returned the error: " . $this->_get_db_error());
		}

		//HOOK: UPDATE hook
		$this->_run_hooks('update', 'any_change');

		return TRUE;
	}

	// --------------------------------------------------------------------

	/**
	 * Deletes a record in the database
	 *
	 * @param int $id
	 * @return boolean
	 */
	function delete($id)
	{
		//HOOK: Pre DELETE hook
		$this->_run_hooks('pre_delete', 'pre_any_change');

		$table_name = $this->table_name;

		//Ensure that the record with that ID actually exists
		if ( ! $this->check_record_exists($id))
			return $this->_do_error("Cannot delete record with ID $id in the table: $table_name.  That record does not exist!");

		$this->db->where('id', $id);
		$result = $this->db->delete($table_name);

		if ( ! $result)
		{
			$this->_record_error("The query you tried to delete the record with was: " . $this->db->last_query());
			return $this->_do_error("Could not delete the record with ID $id in the database; The database server returned the error: " . $this->_get_db_error());
		}

		//HOOK: DELETE hook
		$this->_run_hooks('delete', 'any_change');

		return TRUE;
	}
	
	// --------------------------------------------------------------------
	
	/**
	 * Retrieve all records from the table
	 *
	 * @return array
	 */
	function retrieve_all()
	{
		return $this->retrieve();
	}

	// --------------------------------------------------------------------
	
	/**
	 * Finds records in the database using a single query string
	 *
	 * @param string $query_string The search word
	 * @param array $fields If NULL, then all fields will be searched
	 * @param exact Tells the database query to use '=' rather than 'LIKE'
	 * @return array
	 */
	function find($query_string, $fields = NULL, $exact = FALSE)
	{
		$table_name = $this->table_name;

		if ($fields === NULL)
			$fields = $this->db->list_fields($table_name);
		else
		{
			if ( ! is_array($fields))
				$fields = array((string) $fields);
		}

		foreach($fields as $field_name)
		{
			if ($exact)
				$this->db->or_where($field_name, $query_string);
			else
				$this->db->or_like($field_name, $query_string);
		}

		$result = $this->db->get($table_name);

		if ($result->num_rows() > 0)
			return $result->result();
		else
			return array();
	}

	// --------------------------------------------------------------------

	/**
	 * Find a record in the database using '=' rather
	 * than 'LIKE'
	 *
	 * @param string $query_string The search word
	 * @param array $fields If set to NULL, then all fields will be searched
	 * @return array
	 */
	function find_exact($query_string, $fields = NULL)
	{
		return $this->find($query_string, $fields, TRUE);
	}


	// --------------------------------------------------------------------

	/**
	 * Run any ol' SQL query (hooks work - yay!)
	 *
	 * Substitute _table_ optionally if you wish to insert
	 * the name of this table into the query
	 *
	 * @param string $sql_query
	 * @return boolean|array The result
	 */
	function query($sql_query)
	{
		//Determine hooks
		if (strpos(strtoupper($sql_query), 'INSERT'))
		{
			$pre_hooks = array('pre_insert', 'pre_any_change');
			$post_hooks = array('insert', 'any_change');
		}
		elseif (strpos(strtoupper($sql_query), 'UPDATE'))
		{
			$pre_hooks = array('pre_update', 'pre_any_change');
			$post_hooks = array('update', 'any_change');
		}
		elseif (strpos(strtoupper($sql_query), 'DELETE'))
		{
			$pre_hooks = array('pre_delete', 'pre_any_change');
			$post_hooks = array('delete', 'any_change');
		}

		//Replace _table_ with the name of the table
		$sql_query = str_replace("_table_", $this->db->dbprefix($this->table_name), $sql_query);

		//Run the pre-hooks if there are any
		if (isset($pre_hooks))
			call_user_func_array(array($this, '_run_hooks'), $pre_hooks);

		//Run the Query!
		$result = $this->db->query($sql_query);

		//Run the post-hooks if there are any
		if ($result && isset($post_hooks))
			call_user_func_array(array($this, '_run_hooks'), $post_hooks);

		return $result;
	}

	// --------------------------------------------------------------------
	
	/**
	 * Check if a record exists
	 * 
	 * @param object|array|int The where clause (CodeIgniter-compliant) or ID
	 * @return boolean
	 */
	function check_record_exists($id_or_where_clause)
	{
		if ($this->retrieve_single($id_or_where_clause))
			return TRUE;
		else
			return FALSE;
	}

	// --------------------------------------------------------------------

	/**
	 * Count all of the rows in a table
	 * 
	 * @return int
	 */
	function count_all_rows()
	{
		$result = $this->db->count_all($this->table_name);
		if (is_int($result))
			return $result;
		else
			return $this->_do_error('There was an error getting the number of rows in the table');
	}

	// --------------------------------------------------------------------
	
	/**
	 * Retrieves a random row from the database
	 * 
	 * @return object A random row 
	 */
	function retrieve_random_row()
	{
		if ($rows = $this->count_rows())
		{
			if ($rows > 0)
			{
				$rand = rand(1, $rows);
				return $this->retrieve(NULL, TRUE, $rand, 1);
			}
			else
				return $this->_do_error("Could not retrieve a random value, because there are no records in the table.");
		}
		else
			return $this->_do_error('Could not retrieve a random record, because the model could not determine the number of rows in the database.');

	}

	// --------------------------------------------------------------------
	
	/**
	 * Sorts a column of integers based on another (or the same) column
	 *
	 * @param string $column_to_sort_by
	 * @param string $column_to_update
	 * @param int $start_count_at
	 * @param where $where A CodeIgniter compliant where clause
	 * @return boolean
	 */
	function resort($column_to_sort_by, $column_to_update, $start_count_at = 1, $where = NULL)
	{
		$db_fields = $this->db->list_fields($this->table_name);
		
		if ( ! in_array($column_to_sort_by, $db_fields))
			return $this->_do_error("Cannot sort by column '$column_to_sort_by'.  That column does not exist in the table: {$this->table_name}!");
		if ( ! in_array($column_to_update, $db_fields))
			return $this->_do_error("Cannot update column '$column_to_update'.  That column does not exist in the table: {$this->table_name}!");
		
		$this->db->order_by("$column_to_sort_by ASC");
		$rows = $this->retrieve($where);
		$it_worked = TRUE;
		
		if (count($rows) > 0)
		{
			$count = (int) $start_count_at;
			for($i = 0; $i < count($rows); $i++)
			{
				$curr_row = $rows[$i];
				$data[$column_to_update] = $count;
				if ($this->update($curr_row->id, $data))
					$count++;
				else
				{
					$this->_record_error("Could not update the row with ID {$curr_row->id} while running the resort() function: ". $this->_get_db_error());
					$it_worked = FALSE;
				}				
			}
			
			if ($it_worked == TRUE)
				return TRUE;
			else
				return $this->_do_error("There were errors when running the resort function.");
		}
		else
		{
			$this->_record_error("Cannot resort table {$this->table_name} (where: $where).  No rows returned from query to sort.");
			return NULL;
		}
	}
	
	// --------------------------------------------------------------------
	
	/**
	 * Sorts a column of integers based on another (or the same) column
	 * (shortcut to resort())
	 *
	 * @param string $column_to_sort_by
	 * @param string $column_to_update
	 * @param int $start_count_at
	 * @param where $where A CodeIgniter compliant where clause
	 * @return boolean
	 */
	function sort($column_to_sort_by, $column_to_update, $start_count_at = 1, $where = NULL)
	{
		return $this->resort($column_to_sort_by, $column_to_update, $start_count_at, $where);
	}
	
	// --------------------------------------------------------------------
	
	/**
	 * Sorts a column based on an array of ID's (the table must contain an ID field)
	 *
	 * @param array $list_of_ids
	 * @param string $column_to_update
	 * @param int $start_count_at
	 * @return boolean
	 */
	function resort_by_list($list_of_ids, $column_to_update, $start_count_at = 1)
	{
		$db_fields = $this->db->list_fields($this->table_name);
		
		if ( ! in_array($column_to_update, $db_fields))
			return $this->_do_error("Cannot update column '$column_to_update'.  That column does not exist in the table: {$this->table_name}!");
		if ( ! is_array($list_of_ids))
			return $this->_do_error("list_of_ids (first parameter) must be an array when running the resort_by_list() function!");
			
		$it_worked = TRUE;
		$count = $start_count_at;
		
		foreach($list_of_ids as $id)
		{
			if ($curr_record = $this->retrieve_single($id, FALSE))
			{
				if ($this->update($id, array($column_to_update => $count)))
					$count++;
				else
				{
					$this->_record_error("Could not update the row with ID $id while running the resort() function: ". $this->_get_db_error());
					$it_worked = FALSE;
				}
			}
			else
			{
				$this->_record_error("Cannot update the row with ID {$id}.  That record does not exist in the database!");
				$it_worked = FALSE;
			}
		}
		
		if ($it_worked == TRUE)
			return TRUE;
		else
			return $this->_do_error("There were errors when attempting to resort the table by list.");
	}

	// --------------------------------------------------------------------
	
	/**
	 * Sorts a column based on an array of ID's (the table must contain an ID field)
	 * (shortcut to resort_by_list())
	 *
	 * @param array $list_of_ids
	 * @param string $column_to_update
	 * @param int $start_count_at
	 * @return boolean
	 */
	function sort_by_list($list_of_ids, $column_to_update, $start_count_at = 1)
	{
		return $this->resort_by_list($list_of_ids, $column_to_update, $start_count_at);
	}

	// --------------------------------------------------------------------
	
	/**
	 * Get the column (field) names from the table
	 * 
	 * If $detailed is set to true, this will return an array of objects
	 * with the keys and values representing the attributes for this field.
	 * 
	 * If $detailed is set to false (default), this will simply return
	 * a linear array of field names
	 * 
	 * @param boolean $detailed 
	 * @return array
	 */
	function get_fields($detailed = FALSE)
	{
		if ($detailed === TRUE)
			return $this->_retrieve_db_field_list($this->table_name);
		else
			return $this->db->list_fields($this->table_name);
	}

	// --------------------------------------------------------------------

	/**
	 * Check fields exist for input data
	 * 
	 * Doesn't really do anything useful yet.. work in progress..
	 * 
	 * @access private
	 * @return boolean
	 * TODO: Work on the form generation
	 */
	function _check_fields_exist_for_input_data($input_data)
	{
		$table_name = $this->table_name;

		$errors_found = array();
		foreach($input_data as $field_name => $field_val)
		{
			if ( ! $this->db->field_exists($field_name, $table_name))
				$errors_found[] = "Cannot create or update record!  The field: '$field_name' does not exist in the table: '$table_name'";
		}

		if (count($errors_found) > 0)
		{
			foreach($errors_found as $the_err)
				$this->_record_error($the_err);

			return FALSE;
		}
		else
			return TRUE;
	}

	// --------------------------------------------------------------------
	
	/**
	 * Return an array containing all errors record during
	 * the execution of the code in the model.
	 *
	 * Returns an empty array if no errors exist
	 *
	 * @access public
	 * @return array
	 */
	function get_errors()
	{
		return $this->error_log;
	}

	// --------------------------------------------------------------------

	/**
	 * Attmpts to derive an error message string from the database.
	 * 
	 * Since CodeIgniter doesn't include this functionality built-in (wtf?),
	 * attempt to do it here.
	 * 
	 * This has not yet been thoroughly tested!
	 * 
	 * @access private
	 * @return sring
	 */
	function _get_db_error()
	{
		switch($this->db->dbdriver)
		{
			case 'mysql':
				$error_msg = $this->db->call_function('error');
				break;
			case 'mysqli':
				$error_msg = $this->db->call_function('error');
				break;
			case 'sqlite':
				$error_code = $this->db->call_function('last_error');
				$error_msg = $this->db->call_function('error_string', $error_code);
				break;
			case 'postgre':
				$error_msg = $this->db->call_function('last_error');
				break;
			case 'odbc':
				$error_msg = $this->db->call_function('errormsg');
				break;
			case 'oci8':
				$error_msg = $this->db->call_function('error');
				break;
			case 'mssql':
				$error_msg = $this->db->call_function('get_last_message');
				break;
			default:
				if ($error = $this->db->call_function('error'))
					$error_msg = $error;
				else
					$error_msg = 'unable to retrieve error';
		}

		return $error_msg;
	}

	// --------------------------------------------------------------------

	/**
	 * Load db hooks attemps to laod the database hooks
	 * from the application/config/hooks.php file
	 * 
	 * @access private
	 */
	function _load_db_hooks()
	{
		@include(APPPATH.'config/hooks'.EXT);

		if (isset($db_hook) && is_array($db_hook))
			$this->hooks = $db_hook;
		else
			$this->hooks = array();
	}

	// --------------------------------------------------------------------

	/**
	 * Run hooks attempts to run hooks
	 * 
	 * Accepts indefinite number of strings
	 * (which hooks to attempt to run) 
	 * 
	 * @access private
	 * @param string hook names
	 * @return boolean
	 *
	 */
	function _run_hooks()
	{
		$arg_list = func_get_args();

		if(count($arg_list) < 1)
			return $this->_do_error("You must specify a hook to run!");

		//
		// Hack attack! Load the hooks library into a manual class
		// to get at those private methods...
		//
		$this->load->library('hooks');
		$hook_class = new CI_Hooks;

		foreach($arg_list as $arg)
		{
			if (in_array($arg, array_keys($this->hooks)))
			{
				$to_run = $this->hooks[$arg];
				if (isset($to_run['class']))
					$to_run = array($to_run);

				//Run the hooks
				foreach($to_run as $run_me)
				{
					if ( ! $hook_class->_run_hook($run_me))
						return show_error("There was an error running the database hooks defined for: " . implode(", ", $arg_list));
				}
			}
		}

		//If made ithere, everything seems to have worked!
		return TRUE;
	}

	// --------------------------------------------------------------------

	/**
	 * Setup form types
	 *
	 * Not done yet.. This will map form variables to datatypes in MySQL
	 * 
	 * TODO: Code This!
	 * 
	 * @access private
	 */
	function _setup_form_types()
	{
		$types = array();
		$types['input text']->types = array('char', 'varchar');
		$types['input text']->validation = array();

		$types['input date']->types = array('date', 'datetime', 'timestamp', 'year');
		$types['input date']->validation = array();

		$types['input number']->types = array('int', 'bigint', 'dec', 'decimal', 'double', 'double precision', 'float', 'integer', 'smallint', 'mediumint');
		$types['input number']->validation = array('trim|is_numeric');

		$types['textarea']->types = array('blob', 'enum', 'longblob', 'longtext', 'mediumblob', 'mediumtext', 'text', 'tinyblob', 'tinytext');
		$types['textarea']->validation = array();

		$types['dropdown']->types = array();
		$types['dropdown']->validation = array();

		$types['radio boolean']->types = array('bit', 'boolean', 'tinyint');
		$types['radio boolean']->validation = array();

		$this->form_types = $types;
	}
	
	// --------------------------------------------------------------------
	
	/**
	 * Retrieves the 
	 */
	function _retrieve_db_field_list($table_name = NULL)
	{
		if ($table_name === NULL)
			$table_name = $this->table_name;
			
		//If we're not dealing with a MySQL database....
		if ($this->db->dbdriver != 'mysql' && $this->db->dbdriver != 'mysqli')
			return $this->db->field_data();
			
		//The array that will contain the output
		$out_fields = array();
		
		$fields = $this->db->query("DESCRIBE " . $table_name . ";")->result();
		foreach($fields as $curr_field)
		{											
			$type_const_signed = strtolower($curr_field->Type);
			
			//zerofill
			if (strpos($type_const_signed, 'zerofill') !== FALSE)
			{
				$obj->zerofill = TRUE;
				$type_const_signed = trim(str_replace("zerofill", '', $type_const_signed));
			}
			else
				$obj->zerofill = FALSE;
			
			//unsigned
			if (strpos($type_const_signed, 'unsigned') !== FALSE)
			{
				$obj->unsigned = TRUE;
				$type_const_signed = trim(str_replace("unsigned", '', $type_const_signed));
			}
			else
				$obj->unsigned = FALSE;
				
			//constraint
			if (strpos($type_const_signed, '(') !== FALSE)
			{
				$obj->constraint = trim(substr(str_replace(")", '', trim($type_const_signed)), strpos($type_const_signed, '(')+1));					
				$type_const_signed = trim(substr($type_const_signed, 0, strpos($type_const_signed, '(')));
			}
			else
				$obj->constraint = FALSE;
				
			//type
			$obj->type = $type_const_signed;
			
			//default
			if (isset($curr_field->Default) && $curr_field->Default != NULL)
				$obj->default = $curr_field->Default;
			else
				$obj->default = FALSE;
				
			//primary_key
			if (isset($curr_field->Key) && strtoupper($curr_field->Key) == 'PRI')
				$obj->primary_key = TRUE;
			else
				$obj->primary_key = FALSE;
			
			//null (that's right.. default to TRUE)
			if (isset($curr_field->Null) && strtoupper($curr_field->Null) == "NO")
				$obj->null = FALSE;
			else
				$obj->null = TRUE;
				
			//auto_increment
			if (isset($curr_field->Extra) && strpos(strtolower($curr_field->Extra), 'auto_increment') !== FALSE)
				$obj->auto_increment = TRUE;
			else
				$obj->auto_increment = FALSE;
				
			$out_fields[$curr_field->Field] = $obj;
			unset($obj);
		}
			
		return $out_fields;
	}
	
	/**
	 * Returns the last error recroding during the execution of
	 * the code in the model.  Returns "(no errors)" string if no
	 * errors exist
	 *
	 * @access public
	 * @return string
	 */
	function get_last_error()
	{
		if (count($this->error_log) < 1)
			return "(no errors)";
		else
			return $this->error_log[(count($this->error_log)-1)];
	}

	// --------------------------------------------------------------------

	/**
	 * Adds an error to the errors array in the current model.
	 *
	 * @access private
	 * @param string $error_value
	 * @return boolean Always FALSE
	 */
	function _record_error($error_value)
	{
		$this->error_log[] = $error_value;
	}

	// --------------------------------------------------------------------

	/**
	 * Adds an error to the errors array in the current model and
	 * returns FALSE so that a function can return false and record the
	 * error at the same time.  Ex:
	 *
	 *   if (something_bad_happened())
	 * 		return _do_error("Something just hit the fan!";
	 *
	 * @access private
	 * @param string $error_value
	 * @return boolean Always FALSE
	 */
	function _do_error($error_value)
	{
		$this->_record_error($error_value);
		return FALSE;
	}
	
	// --------------------------------------------------------------------
	
	/**
   * Converts an object to an array (recursively)
   * 
   * @access private
   * @param object $object
   * @return array
	 */
	function _object_to_array($object)
	{
		if( ! is_object($object) && ! is_array($object))
			return $object;
			
		if(is_object($object))
			$object = get_object_vars($object);
		
		return array_map(array($this, '_object_to_array'), $object);
	}	
}

/* End of file My_Model.php */
/* Location: ./system/application/libraries/MY_Model.php */